﻿Public Class iniFile

#Region "Virables"
    Private keyPairs As New Dictionary(Of SectionPair, String)
    Private myFilePath As String
    Private myAutoSave As Boolean
    Private myAutoAddNotExists As Boolean
    Private myAutoCreateNotExists As Boolean

    Structure SectionPair
        Dim Section As String
        Dim Key As String
    End Structure
#End Region

#Region "New"
    Public Sub New(path As String)
        Me.New(path, False, False, False)
    End Sub
    Public Sub New(path As String, autoCreateNotExists As Boolean)
        Me.New(path, autoCreateNotExists, False, False)
    End Sub
    Public Sub New(path As String, autoCreateNotExists As Boolean, autoAddNotExists As Boolean)
        Me.New(path, autoCreateNotExists, autoAddNotExists, False)
    End Sub
    Public Sub New(path As String, autoCreateNotExists As Boolean, autoAddNotExists As Boolean, autoSave As Boolean)
        Dim reader As IO.StreamReader = Nothing
        Dim strLine As String = Nothing
        Dim currentRoot As String = Nothing
        Dim keyPair As String() = Nothing

        Me.FilePath = path
        Me.AutoSave = autoSave
        Me.AutoAddNotExists = autoAddNotExists
        Me.AutoCreateNotExists = autoCreateNotExists

        Try
            If IO.File.Exists(path) Then
                reader = New IO.StreamReader(path)

                While Not reader.EndOfStream
                    'Read Line
                    strLine = Trim(reader.ReadLine())

                    'Empty Line
                    If strLine = "" Then Continue While

                    'Comments
                    If strLine.StartsWith("#") OrElse strLine.StartsWith(";") Then Continue While

                    'Root
                    If strLine.StartsWith("[") AndAlso strLine.EndsWith("]") Then
                        currentRoot = Trim(strLine.Substring(1, strLine.Length - 2))
                        Continue While
                    End If

                    'If no root add default root
                    If currentRoot Is Nothing Then
                        currentRoot = "ROOT"
                    End If

                    'Section, Key, Value
                    If Not strLine.Contains("=") Then Continue While
                    keyPair = strLine.Split({"="}, 2, StringSplitOptions.None)

                    Dim sectionPair As SectionPair
                    Dim value As String = Nothing

                    sectionPair.Section = currentRoot
                    sectionPair.Key = keyPair(0)

                    If keyPair.Length > 1 Then
                        value = keyPair(1)
                    End If

                    If Not keyPairs.ContainsKey(sectionPair) Then
                        keyPairs.Add(sectionPair, System.Text.RegularExpressions.Regex.Unescape(value))
                    End If
                End While
            Else
                If autoCreateNotExists Then
                    IO.File.Create(path).Close()
                End If
                'Throw New IO.FileNotFoundException("Unable to locate " + iniFilePath)
            End If
        Catch ex As Exception
            Throw ex
        Finally
            If reader IsNot Nothing Then
                reader.Close()
            End If
        End Try
    End Sub
#End Region

#Region "Get Value"
    ''' <summary>
    ''' Returns the value for the given section, key pair.
    ''' </summary>
    ''' <param name="sectionName">Section name.</param>
    ''' <param name="settingName">Key name.</param>
    Public Function GetSetting(sectionName As String, settingName As String) As String
        Return GetSetting(sectionName, settingName, "")
    End Function
    ''' <summary>
    ''' Returns the value for the given section, key pair.
    ''' </summary>
    ''' <param name="sectionName">Section name.</param>
    ''' <param name="settingName">Key name.</param>
    ''' <param name="defaultValue">Default value.</param>
    Public Function GetSetting(sectionName As String, settingName As String, defaultValue As String) As String
        Dim sectionPair As SectionPair
        sectionPair.Section = sectionName
        sectionPair.Key = settingName

        If keyPairs.ContainsKey(sectionPair) Then
            Return keyPairs(sectionPair)
        Else
            Return defaultValue
        End If
    End Function

    ''' <summary>
    ''' Enumerates all lines for given section.
    ''' </summary>
    ''' <param name="sectionName">Section to enum.</param>
    Public Function EnumSection(sectionName As String) As String()
        Dim tmpArray As New ArrayList()

        For Each pair In keyPairs.Keys
            If pair.Section = sectionName Then
                tmpArray.Add(pair.Key)
            End If
        Next

        Return tmpArray.ToArray()
    End Function
#End Region

#Region "Add Value"
    ''' <summary>
    ''' Adds or replaces a setting to the table to be saved with a null value.
    ''' </summary>
    ''' <param name="sectionName">Section to add under.</param>
    ''' <param name="settingName">Key name to add.</param>
    Public Sub AddSetting(sectionName As String, settingName As String)
        AddSetting(sectionName, settingName, "", Me.AutoSave)
    End Sub
    ''' <summary>
    ''' Adds or replaces a setting to the table to be saved.
    ''' </summary>
    ''' <param name="sectionName">Section to add under.</param>
    ''' <param name="settingName">Key name to add.</param>
    ''' <param name="settingValue">Value of key.</param>
    Public Sub AddSetting(sectionName As String, settingName As String, settingValue As String)
        AddSetting(sectionName, settingName, settingValue, Me.AutoSave)
    End Sub
    Public Sub AddSetting(sectionName As String, settingName As String, settingValue As String, SaveSetting As Boolean)
        Dim sectionPair As SectionPair
        sectionPair.Section = sectionName
        sectionPair.Key = settingName

        If keyPairs.ContainsKey(sectionPair) Then
            keyPairs(sectionPair) = settingValue
        Else
            keyPairs.Add(sectionPair, settingValue)
        End If

        If SaveSetting Then
            Call SaveSettings()
        End If
    End Sub
#End Region

#Region "Edit Value"
    Public Sub EditSetting(sectionName As String, settingName As String)
        Call EditSetting(sectionName, settingName, "", Me.AutoAddNotExists, Me.AutoSave)
    End Sub
    ''' <summary>
    ''' Edit a setting to the table to be saved.
    ''' </summary>
    ''' <param name="sectionName">Section.</param>
    ''' <param name="settingName">Key</param>
    ''' <param name="settingValue">Edit Value of key.</param>
    Public Sub EditSetting(sectionName As String, settingName As String, settingValue As String)
        Call EditSetting(sectionName, settingName, settingValue, Me.AutoAddNotExists, Me.AutoSave)
    End Sub
    Public Sub EditSetting(sectionName As String, settingName As String, settingValue As String, AutoAddNotExists As Boolean)
        Call EditSetting(sectionName, settingName, settingValue, AutoAddNotExists, Me.AutoSave)
    End Sub
    Public Sub EditSetting(sectionName As String, settingName As String, settingValue As String, AutoAddNotExist As Boolean, SaveSetting As Boolean)
        Dim sectionPair As SectionPair
        sectionPair.Section = sectionName
        sectionPair.Key = settingName

        If keyPairs.ContainsKey(sectionPair) Then
            keyPairs(sectionPair) = settingValue

            If SaveSetting Then
                Call SaveSettings()
            End If
        Else
            If AutoAddNotExist Then
                Call AddSetting(sectionName, settingName, settingValue, SaveSetting)
            End If
        End If
    End Sub
#End Region

#Region "Delete Value"
    Public Sub DeleteSetting(sectionName As String, settingName As String)
        Call DeleteSetting(sectionName, settingName, Me.AutoSave)
    End Sub
    ''' <summary>
    ''' Remove a setting.
    ''' </summary>
    ''' <param name="sectionName">Section to add under.</param>
    ''' <param name="settingName">Key name to add.</param>
    Public Sub DeleteSetting(sectionName As String, settingName As String, SaveSetting As Boolean)
        Dim sectionPair As SectionPair
        sectionPair.Section = sectionName
        sectionPair.Key = settingName

        If keyPairs.ContainsKey(sectionPair) Then
            keyPairs.Remove(sectionPair)
        End If

        If SaveSetting Then
            Call SaveSettings()
        End If
    End Sub
#End Region

#Region "Save Value"
    ''' <summary>
    ''' Save settings back to ini file.
    ''' </summary>
    Public Sub SaveSettings()
        SaveSettings(Me.FilePath)
    End Sub

    ''' <summary>
    ''' Save settings to new file.
    ''' </summary>
    ''' <param name="newFilePath">New file path.</param>
    Public Sub SaveSettings(newFilePath As String)
        Dim sections As New ArrayList()
        Dim tmpValue As String = ""
        Dim strToSave As String = ""

        For Each sectionPair As Object In keyPairs.Keys
            If Not sections.Contains(sectionPair.Section) Then
                sections.Add(sectionPair.Section)
            End If
        Next

        For Each section As String In sections
            strToSave &= "[" & section & "]" & vbCrLf

            For Each sectionPair In keyPairs.Keys
                If sectionPair.Section = section Then
                    tmpValue = keyPairs(sectionPair)

                    If tmpValue IsNot Nothing Then
                        tmpValue = System.Text.RegularExpressions.Regex.Escape(tmpValue)
                    End If

                    strToSave &= sectionPair.Key & "=" & tmpValue & vbCrLf
                End If
            Next

            strToSave &= vbCrLf
        Next

        Try
            Dim tw As New IO.StreamWriter(newFilePath, False)
            tw.Write(strToSave)
            tw.Close()
        Catch ex As Exception
            Throw ex
        End Try
    End Sub
#End Region

#Region "Property"
    Default Public ReadOnly Property Item(sectionName As String, settingName As String) As String
        Get
            Return GetSetting(sectionName, settingName, "")
        End Get
    End Property
    Default Public ReadOnly Property Item(sectionName As String, settingName As String, defaultValue As String) As String
        Get
            Return GetSetting(sectionName, settingName, defaultValue)
        End Get
    End Property
    Public Property FilePath As String
        Get
            Return myFilePath
        End Get
        Set(value As String)
            myFilePath = value
        End Set
    End Property
    Public Property AutoSave As Boolean
        Get
            Return myAutoSave
        End Get
        Set(value As Boolean)
            myAutoSave = value
        End Set
    End Property
    Public Property AutoAddNotExists As Boolean
        Get
            Return myAutoAddNotExists
        End Get
        Set(value As Boolean)
            myAutoAddNotExists = value
        End Set
    End Property
    Public Property AutoCreateNotExists As Boolean
        Get
            Return myAutoCreateNotExists
        End Get
        Set(value As Boolean)
            myAutoCreateNotExists = value
        End Set
    End Property
#End Region
End Class